/*
 * Copyright (c) 2013 Johann Hanne
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef _FRMGRB_H
#define _FRMGRB_H

#include <stdint.h>
#include <portio.h>
#include <i86.h>

#define frmgrb_set_destination_address(segaddr) \
    do { \
        outpw(0xa22, (SEGADDR_TO_PHYSADDR(segaddr) & 0xffff0000ul) >> 16); \
        outpw(0xa20,  SEGADDR_TO_PHYSADDR(segaddr) & 0x0000fffful); \
    } while (0)

#define frmgrb_set_rectangle(x1, y1, x2, y2) \
    do { \
        outpw(0xa06, (uint16_t)(x1) & 0x07ffu); \
        outpw(0xa08, (uint16_t)(y1) & 0x07ffu); \
        outpw(0xa0a, (uint16_t)(x2) & 0x07ffu); \
        outpw(0xa0c, (uint16_t)(y2) & 0x07ffu); \
    } while (0)

#define frmgrb_control(val1, val2) \
    do { \
        outpw(0xa00, (uint16_t)(val2)); \
        outpw(0xa04, (uint16_t)(val1)); \
    } while (0)

#define frmgrb_status() \
    inpw(0xa00)

#define frmgrb_set_summer1_rectangle(x1, y1, x2, y2) \
    do { \
        outpw(0xa82, (uint16_t)(x1) & 0x07ffu); \
        outpw(0xa84, (uint16_t)(y1) & 0x07ffu); \
        outpw(0xa86, (uint16_t)(x2) & 0x07ffu); \
        outpw(0xa88, (uint16_t)(y2) & 0x07ffu); \
    } while (0)

#define frmgrb_get_summer1_sums(r, g1, g2, b) \
    do { \
        (*(r)) = inpw(0xa80); \
        (*(g1)) = inpw(0xa82); \
        (*(g2)) = inpw(0xa84); \
        (*(b)) = inpw(0xa86); \
    } while (0)

#define frmgrb_set_summer2_rectangle(x1, y1, x2, y2) \
    do { \
        outpw(0xa8a, (uint16_t)(x1) & 0x07ffu); \
        outpw(0xa8c, (uint16_t)(y1) & 0x07ffu); \
        outpw(0xa8e, (uint16_t)(x2) & 0x07ffu); \
        outpw(0xa90, (uint16_t)(y2) & 0x07ffu); \
    } while (0)

#define frmgrb_get_summer2_sums(r, g, b) \
    do { \
        (*(r)) = inpw(0xa88); \
        (*(g)) = inpw(0xa8a); \
        (*(b)) = inpw(0xa8c); \
    } while (0)

#define frmgrb_set_summer3_rectangle(x1, y1, x2, y2) \
    do { \
        outpw(0xa92, (uint16_t)(x1) & 0x07ffu); \
        outpw(0xa94, (uint16_t)(y1) & 0x07ffu); \
        outpw(0xa96, (uint16_t)(x2) & 0x07ffu); \
        outpw(0xa98, (uint16_t)(y2) & 0x07ffu); \
    } while (0)

#define frmgrb_get_summer3_sums(r, g, b) \
    do { \
        (*(r)) = inpw(0xa8e); \
        (*(g)) = inpw(0xa90); \
        (*(b)) = inpw(0xa92); \
    } while (0)

#define frmgrb_set_summer4_rectangle(x1, y1, x2, y2) \
    do { \
        outpw(0xa9a, (uint16_t)(x1) & 0x07ffu); \
        outpw(0xa9c, (uint16_t)(y1) & 0x07ffu); \
        outpw(0xa9e, (uint16_t)(x2) & 0x07ffu); \
        outpw(0xaa0, (uint16_t)(y2) & 0x07ffu); \
    } while (0)

#define frmgrb_get_summer4_sums(r, g, b) \
    do { \
        (*(r)) = inpw(0xa94); \
        (*(g)) = inpw(0xa96); \
        (*(b)) = inpw(0xa9a); \
    } while (0)

#define frmgrb_set_summer5_rectangle(x1, y1, x2, y2) \
    do { \
        outpw(0xaa2, (uint16_t)(x1) & 0x07ffu); \
        outpw(0xaa4, (uint16_t)(y1) & 0x07ffu); \
        outpw(0xaa6, (uint16_t)(x2) & 0x07ffu); \
        outpw(0xaa8, (uint16_t)(y2) & 0x07ffu); \
    } while (0)

#define frmgrb_get_summer5_sums(r, g, b) \
    do { \
        (*(r)) = inpw(0xa98); \
        (*(g)) = inpw(0xa9c); \
        (*(b)) = inpw(0xa9e); \
    } while (0)

#define frmgrb_set_summer6_rectangle(x1, y1, x2, y2) \
    do { \
        outpw(0xaaa, (uint16_t)(x1) & 0x07ffu); \
        outpw(0xaac, (uint16_t)(y1) & 0x07ffu); \
        outpw(0xaae, (uint16_t)(x2) & 0x07ffu); \
        outpw(0xab0, (uint16_t)(y2) & 0x07ffu); \
    } while (0)

#define frmgrb_get_summer6_sums(r, g, b) \
    do { \
        (*(r)) = inpw(0xaa0); \
        (*(g)) = inpw(0xaa2); \
        (*(b)) = inpw(0xaa4); \
    } while (0)

#define frmgrb_set_summer_divider(unknown, shift) \
    do { \
        outpw(0xa80, ((unknown) & 0xf) | ((shift & 0xf) << 4)); \
    } while (0)

int frmgrb_init(void);

#endif /* _FRMGRB_H */
